﻿using FanKit.Transformers;
using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Effects;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.Storage.Streams;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“空白页”项模板

namespace TestApp4
{
    /// <summary>
    /// 可用于自身或导航至 Frame 内部的空白页。
    /// </summary>
    public sealed partial class FreeTransformPage : Page
    {
        /// <summary>
        /// 图像大小
        /// </summary>
        int imageWidth;
        int imageHeight;

        int thumbSize = 10;

        CanvasBitmap originBitmp;

        byte[] freeTranCode;


        Transformer des = new Transformer
        {
            LeftTop = new Vector2(0, 0),
            RightTop = new Vector2(1, 0),
            RightBottom = new Vector2(1, 1),
            LeftBottom = new Vector2(0, 1),
        };

        Transformer source = new Transformer
        {
            LeftTop = new Vector2(0, 0),
            RightTop = new Vector2(1, 0),
            RightBottom = new Vector2(1, 1),
            LeftBottom = new Vector2(0, 1),
        };

        public FreeTransformPage()
        {
            this.InitializeComponent();
            Init();
        }



        void Init()
        {
            ltt.DragDelta += DragDelta;
            rtt.DragDelta += DragDelta;
            lbt.DragDelta += DragDelta;
            rbt.DragDelta += DragDelta;

            bt.Click += (s, e) =>
            {
                SelectImage();
            };

            //创建资源
            canvas.CreateResources += (s, e) =>
            {
                e.TrackAsyncAction(CreateResourcesAsync().AsAsyncAction());
            };

            canvas.Draw += (s, e) =>
            {
                if (originBitmp != null && freeTranCode != null)
                {
                    e.DrawingSession.Units = CanvasUnits.Pixels;

                    Matrix3x2 matrix = Transformer.FindHomography(source, des, out Vector2 distance);
                    PixelShaderEffect pse = new PixelShaderEffect(freeTranCode)
                    {
                        Source1 = originBitmp,
                        Properties =
                        {
                            ["matrix4"] = new Matrix4x4(matrix),
                            ["distce"] = distance,
                            ["w"] = (float)imageWidth,
                            ["h"] = (float)imageHeight,
                        },
                    };

                    e.DrawingSession.DrawImage(new ScaleEffect
                    {
                        Scale = new Vector2(s.Dpi / 96),
                        Source = pse
                    });


                    e.DrawingSession.Units = CanvasUnits.Dips;

                    e.DrawingSession.DrawLine(des.LeftTop, des.RightTop, Colors.Red);
                    e.DrawingSession.DrawLine(des.RightTop, des.RightBottom, Colors.Red);
                    e.DrawingSession.DrawLine(des.RightBottom, des.LeftBottom, Colors.Red);
                    e.DrawingSession.DrawLine(des.LeftBottom, des.LeftTop, Colors.Red);

                    e.DrawingSession.DrawLine(source.LeftTop, source.RightTop, Colors.Red);
                    e.DrawingSession.DrawLine(source.RightTop, source.RightBottom, Colors.Red);
                    e.DrawingSession.DrawLine(source.RightBottom, source.LeftBottom, Colors.Red);
                    e.DrawingSession.DrawLine(source.LeftBottom, source.LeftTop, Colors.Red);
                }
            };



        }

        public async void SelectImage()
        {
            FileOpenPicker picker = new FileOpenPicker() { FileTypeFilter = { ".jpg", ".png" } };
            StorageFile file = await picker.PickSingleFileAsync();
            if (file == null)
            {
                imageHeight = 0;
                imageWidth = 0;
                ltt.Visibility = rtt.Visibility = lbt.Visibility = rbt.Visibility = Visibility.Collapsed;
                originBitmp = null;
                return;
            }

            originBitmp = await CanvasBitmap.LoadAsync(CanvasDevice.GetSharedDevice(), await file.OpenReadAsync());
            imageHeight = (int)originBitmp.SizeInPixels.Height;
            imageWidth = (int)originBitmp.SizeInPixels.Width;
            des = new Transformer
            {
                LeftTop = new Vector2(0, 0),
                RightTop = new Vector2(imageWidth, 0),
                RightBottom = new Vector2(imageWidth, imageHeight),
                LeftBottom = new Vector2(0, imageHeight),
            };

            source = new Transformer
            {
                LeftTop = new Vector2(0, 0),
                RightTop = new Vector2(imageWidth, 0),
                RightBottom = new Vector2(imageWidth, imageHeight),
                LeftBottom = new Vector2(0, imageHeight),
            };


            ltt.Visibility = rtt.Visibility = lbt.Visibility = rbt.Visibility = Visibility.Visible;
            SetThumbPosition();
            canvas.Invalidate();
        }

        private async Task CreateResourcesAsync()
        {
            //ms - appx:///Assets/Shader/LiqueArea.txt
            this.freeTranCode = await LoadAsync("ms-appx:///Assets/FreeTranform.txt");
        }

        public static async Task<byte[]> LoadAsync(string path)
        {
            StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(path));
            IBuffer buffer = await FileIO.ReadBufferAsync(file);
            return buffer.ToArray();
        }

        void SetThumbPosition()
        {
            if (originBitmp != null)
            {
                //Vector2 size = new Vector2(imageWidth, imageHeight);
                //ltt.Translation = new Vector3(source.LeftTop * size, 0);
                //rtt.Translation = new Vector3(source.RightTop * size, 0);
                //lbt.Translation = new Vector3(source.LeftBottom * size, 0);
                //rbt.Translation = new Vector3(source.RightBottom * size, 0);

                Vector2 size = new Vector2(imageWidth, imageHeight);
                ltt.Translation = new Vector3(source.LeftTop, 0);
                rtt.Translation = new Vector3(source.RightTop, 0);
                lbt.Translation = new Vector3(source.LeftBottom, 0);
                rbt.Translation = new Vector3(source.RightBottom, 0);
            }
        }

        private void DragDelta(object sender, DragDeltaEventArgs e)
        {
            var th = (Thumb)sender;
            //var ox = ((float)e.HorizontalChange / imageWidth);
            //var oy = ((float)e.VerticalChange / imageHeight);

            var ox = ((float)e.HorizontalChange);
            var oy = ((float)e.VerticalChange);
            switch (th.Name)
            {
                case "ltt":
                    source.LeftTop += new Vector2(ox, oy);
                    break;
                case "rtt":
                    source.RightTop += new Vector2(ox, oy);
                    break;
                case "lbt":
                    source.LeftBottom += new Vector2(ox, oy);
                    break;
                case "rbt":
                    source.RightBottom += new Vector2(ox, oy);
                    break;
            }

            SetThumbPosition();
            canvas.Invalidate();
        }
    }
}
